package com.ftr.video.fpv;

import android.content.Intent;
import android.content.SharedPreferences;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

import com.serenegiant.common.BaseActivity;
import com.serenegiant.encoder.MediaMuxerWrapper;
import com.serenegiant.usb.CameraDialog;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.USBMonitor.OnDeviceConnectListener;
import com.serenegiant.usb.USBMonitor.UsbControlBlock;
import com.serenegiant.usb.UVCCamera;
import com.serenegiant.usbcameracommon.UVCCameraHandlerMultiSurface;
import com.serenegiant.widget.CameraViewInterface;
import com.serenegiant.widget.UVCCameraTextureView;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public final class MainActivity extends BaseActivity implements CameraDialog.CameraDialogParent {
    private static final boolean DEBUG = true;	// TODO set false on release
    private static final String TAG = "MainActivity";

    private final Object mSync = new Object();
    /**
     * for accessing USB
     */
    private USBMonitor mUSBMonitor;
    /**
     * Handler to execute camera releated methods sequentially on private thread
     */
    private UVCCameraHandlerMultiSurface mCameraHandler;
    /**
     * for camera preview display
     */
    private CameraViewInterface mUVCCameraViewL;
    private CameraViewInterface mUVCCameraViewR;
    /**
     * for open&start / stop&close camera preview
     */
    private ImageButton mCameraButton;
    /**
     * button for start/stop recording
     */
    private ImageButton mCaptureButton;
    private ImageButton mVRButton;
    private View mRotateButton;

    View.OnTouchListener m_PressRed = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            ImageButton ib = (ImageButton) view;
            switch (motionEvent.getAction()){
                case MotionEvent.ACTION_DOWN:
                    ib.setColorFilter(0xffff0000);	// turn red
                    break;
                case MotionEvent.ACTION_UP:
                    ib.setColorFilter(0);
                    break;
            }
            return false;
        }
    };

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (DEBUG) Log.v(TAG, "onCreate:");
        setContentView(R.layout.activity_main);

        mRotateButton = findViewById(R.id.rotate_Button);
        mRotateButton.setOnClickListener(mOnClickListener);
        mRotateButton.setOnTouchListener(m_PressRed);

        mCameraButton = (ImageButton)findViewById(R.id.camera_button);
        mCameraButton.setOnClickListener(mOnClickListener);
        mCameraButton.setOnTouchListener(m_PressRed);

        mCaptureButton = (ImageButton)findViewById(R.id.capture_button);
        mCaptureButton.setOnClickListener(mOnClickListener);
        mCaptureButton.setVisibility(View.INVISIBLE);

        mUVCCameraViewL = (CameraViewInterface)findViewById(R.id.camera_view_L);
        mUVCCameraViewL.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float)UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        mUVCCameraViewL.setCallback(mCallback);

        mUVCCameraViewR = (CameraViewInterface)findViewById(R.id.camera_view_R);
        mUVCCameraViewR.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float)UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        mUVCCameraViewR.setCallback(mCallback);


        mVRButton = (ImageButton)findViewById(R.id.VRSwitchButton);
        mVRButton.setOnTouchListener(m_PressRed);

        mVRButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                vrClick();
            }
        });
        synchronized (mSync) {
            mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);
            mCameraHandler = UVCCameraHandlerMultiSurface.createHandler(this, mUVCCameraViewL, 1,
                    UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        }

        SharedPreferences read = getSharedPreferences("appdata", MODE_PRIVATE);
        if(!read.getBoolean("firstrun", true)){
            View viewTips = findViewById(R.id.tips_imageView);
            viewTips.setVisibility(View.GONE);
        }else{
            View viewTips = findViewById(R.id.tips_imageView);
            viewTips.setClickable(true);
            viewTips.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    view.setVisibility(View.GONE);

                    //步骤2-1：创建一个SharedPreferences.Editor接口对象，lock表示要写入的XML文件名，MODE_WORLD_WRITEABLE写操作
                    SharedPreferences.Editor editor = getSharedPreferences("appdata", MODE_PRIVATE).edit();
                    //步骤2-2：将获取过来的值放入文件
                    editor.putBoolean("firstrun", false);
                    //步骤3：提交
                    editor.commit();
                }
            });
        }

    }


    private void cameraStart(CameraViewInterface cvi){
        if (cvi != null) {
            cvi.onResume();
        }
    }
    private void cameraStop(CameraViewInterface cvi){
        if (cvi != null) {
            cvi.onPause();
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
            UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
            Toast.makeText(this, "onNewIntent calll", Toast.LENGTH_SHORT).show();
        }
    }

    private void vrClick(){
        synchronized (mSync) {
            mCameraHandler.close();	// #close include #stopRecording and #stopPreview
            mUSBMonitor.unregister();
        }
        cameraStop(mUVCCameraViewL);
        cameraStop(mUVCCameraViewR);
        RelativeLayout viewR = (RelativeLayout)findViewById(R.id.camera_layout_R);
        RelativeLayout viewL = (RelativeLayout)findViewById(R.id.camera_layout_L);
        viewL.removeViewInLayout((View) mUVCCameraViewL);
        viewR.removeViewInLayout((View) mUVCCameraViewR);
        RelativeLayout.LayoutParams viewLayout = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        viewLayout.addRule(RelativeLayout.CENTER_HORIZONTAL);
        viewLayout.addRule(RelativeLayout.CENTER_VERTICAL);

        mUVCCameraViewL = new UVCCameraTextureView(this);
        ((View)mUVCCameraViewL).setLayoutParams(viewLayout);
        mUVCCameraViewL.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float)UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        mUVCCameraViewL.setCallback(mCallback);

        mUVCCameraViewR = new UVCCameraTextureView(this);
        ((View)mUVCCameraViewR).setLayoutParams(viewLayout);
        mUVCCameraViewR.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float)UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        mUVCCameraViewR.setCallback(mCallback);

        viewL.addView((View) mUVCCameraViewL);
        viewR.addView((View) mUVCCameraViewR);
        viewL.setVisibility(View.VISIBLE);
        if(viewR.getVisibility() == View.GONE) {
            viewR.setVisibility(View.VISIBLE);
        }else{
            viewR.setVisibility(View.GONE);
        }
        synchronized (mSync) {
            mUSBMonitor.register();
        }

        cameraStart(mUVCCameraViewL);
        cameraStart(mUVCCameraViewR);

    }
    @Override
    protected void onStart() {
        super.onStart();
        if (DEBUG) Log.v(TAG, "onStart:");
        synchronized (mSync) {
            mUSBMonitor.register();
        }

        cameraStart(mUVCCameraViewL);
        cameraStart(mUVCCameraViewR);
    }

    @Override
    protected void onStop() {
        if (DEBUG) Log.v(TAG, "onStop:");
        synchronized (mSync) {
//			mCameraHandler.stopRecording();
//			mCameraHandler.stopPreview();
            mCameraHandler.close();	// #close include #stopRecording and #stopPreview
            mUSBMonitor.unregister();
        }
        cameraStop(mUVCCameraViewL);
        cameraStop(mUVCCameraViewR);

        super.onStop();
    }

    @Override
    public void onDestroy() {
        if (DEBUG) Log.v(TAG, "onDestroy:");
        synchronized (mSync) {
            if (mCameraHandler != null) {
                mCameraHandler.release();
                mCameraHandler = null;
            }
            if (mUSBMonitor != null) {
                mUSBMonitor.destroy();
                mUSBMonitor = null;
            }
        }
        mUVCCameraViewL = null;
        mUVCCameraViewR = null;
        mCameraButton = null;
        mCaptureButton = null;
        super.onDestroy();
    }

    private final int MSG_TAKE_PICURE = 0x100000;
    private long m_take_picture_time = 0;
    private Handler m_Handle = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_TAKE_PICURE:
                    if(msg.getWhen()-m_take_picture_time<200){
                        return;
                    }
                    m_take_picture_time = msg.getWhen();

                    m_playKacaSound.run();

                    synchronized (mSync) {
                        if ((mCameraHandler != null) && mCameraHandler.isOpened()) {
                            if (checkPermissionWriteExternalStorage()) {
                                final File outputFile = MediaMuxerWrapper.getCaptureFile(Environment.DIRECTORY_DCIM, ".png");
                                mCameraHandler.captureStill(outputFile.toString());
                            }
                        }
                    }
                    break;
            }
        }
    };
    private Date mStartDate;

    private Runnable m_showRecordTime = new Runnable() {
        @Override
        public void run() {
            Date curDate = new Date(System.currentTimeMillis());
            long diff = curDate.getTime() - mStartDate.getTime();
            Date diffDate = new Date(diff);

            TextView tvRecordTime = findViewById(R.id.tv_recordtime);
            SimpleDateFormat myFmt1=new SimpleDateFormat("HH:mm:ss");
            myFmt1.setTimeZone(TimeZone.getTimeZone("GMT"));

            tvRecordTime.setText(myFmt1.format(diffDate));

            m_Handle.postDelayed(this, 1000);
        }
    };

    private Runnable m_playKacaSound = new Runnable() {
        @Override
        public void run() {
            MediaPlayer music;
            music = MediaPlayer.create(MainActivity.this, R.raw.kaca);
            music.start();
        }
    };
    /**
     * event handler when click camera / capture button
     */
    private final OnClickListener mOnClickListener = new OnClickListener() {
        @Override
        public void onClick(final View view) {
            switch (view.getId()) {
                case R.id.capture_button:
                    synchronized (mSync) {
                        if ((mCameraHandler != null) && mCameraHandler.isOpened()) {
                            if (checkPermissionWriteExternalStorage() && checkPermissionAudio()) {
                                if (!mCameraHandler.isRecording()) {
                                    mCaptureButton.setColorFilter(0xffff0000);	// turn red
                                    mCameraHandler.startRecording();

                                    mStartDate = new Date(System.currentTimeMillis());
                                    TextView tvRecordTime = findViewById(R.id.tv_recordtime);
                                    tvRecordTime.setText("");
                                    tvRecordTime.setVisibility(View.VISIBLE);
                                    m_Handle.postDelayed(m_showRecordTime, 1000);

                                } else {
                                    TextView tvRecordTime = findViewById(R.id.tv_recordtime);
                                    tvRecordTime.setVisibility(View.GONE);

                                    m_Handle.removeCallbacks(m_showRecordTime);
                                    mCaptureButton.setColorFilter(0);	// return to default color
                                    mCameraHandler.stopRecording();
                                }
                            }
                        }
                    }
                    break;
                case R.id.camera_button:
                    m_Handle.sendEmptyMessage(MSG_TAKE_PICURE);
                    break;
                case R.id.rotate_Button:
                    synchronized (mSync) {
                        View viewR = (View) mUVCCameraViewR;
                        if (viewR.getVisibility() != View.GONE) {
                            if ((int) viewR.getRotation() == 360) {
                                viewR.setRotation(0.0F);
                            }
                            viewR.setRotation(viewR.getRotation() + 90.0F);
                        }

                        View viewL = (View) mUVCCameraViewL;
                        if ((int) viewL.getRotation() == 360) {
                            viewL.setRotation(0.0F);
                        }
                        viewL.setRotation(viewL.getRotation() + 90.0F);
                    }
                    break;
            }
        }
    };

    private final CompoundButton.OnCheckedChangeListener mOnCheckedChangeListener
            = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(final CompoundButton compoundButton, final boolean isChecked) {
            switch (compoundButton.getId()) {
                case R.id.camera_button:
                    synchronized (mSync) {
                        if (isChecked && (mCameraHandler != null) && !mCameraHandler.isOpened()) {
                            CameraDialog.showDialog(MainActivity.this);
                        } else {
                            mCameraHandler.close();
                        }
                    }
                    break;
            }
        }
    };


    private void startPreview() {
        synchronized (mSync) {
            if (mCameraHandler != null) {
                mCameraHandler.startPreview();
            }
        }
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mCaptureButton.setVisibility(View.VISIBLE);
            }
        });
    }

    private final OnDeviceConnectListener mOnDeviceConnectListener = new OnDeviceConnectListener() {
        @Override
        public void onAttach(final UsbDevice device) {
            if (DEBUG) Log.v(TAG, "onAttach:");
            mUSBMonitor.requestPermission(device);
        }

        @Override
        public void onConnect(final UsbDevice device, final UsbControlBlock ctrlBlock, final boolean createNew) {
            if (DEBUG) Log.v(TAG, "onConnect:");
            synchronized (mSync) {
                if (mCameraHandler != null) {
                    mCameraHandler.open(ctrlBlock);
                    startPreview();
                }
            }
        }

        @Override
        public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) {
            if (DEBUG) Log.v(TAG, "onDisconnect:");
            synchronized (mSync) {
                if (mCameraHandler != null) {
                    queueEvent(new Runnable() {
                        @Override
                        public void run() {
                            synchronized (mSync) {
                                if (mCameraHandler != null) {
                                    mCameraHandler.close();
                                }
                            }
                        }
                    }, 0);
                }
            }
        }

        @Override
        public void onDettach(final UsbDevice device) {
            if (DEBUG) Log.v(TAG, "onDettach:");
        }

        @Override
        public void onCancel(final UsbDevice device) {
        }
    };

    /**
     * to access from CameraDialog
     * @return
     */
    @Override
    public USBMonitor getUSBMonitor() {
        synchronized (mSync) {
            return mUSBMonitor;
        }
    }

    @Override
    public void onDialogResult(boolean canceled) {
        if (canceled) {

        }
    }

    private final CameraViewInterface.Callback
            mCallback = new CameraViewInterface.Callback() {
        @Override
        public void onSurfaceCreated(final CameraViewInterface view, final Surface surface) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mCameraHandler.addSurface(surface.hashCode(), surface, false);

                }
            }, 2000);
        }

        @Override
        public void onSurfaceChanged(final CameraViewInterface view, final Surface surface, final int width, final int height) {
        }

        @Override
        public void onSurfaceDestroy(final CameraViewInterface view, final Surface surface) {
            synchronized (mSync) {
                if (mCameraHandler != null) {
                    mCameraHandler.removeSurface(surface.hashCode());
                }
            }
        }
    };

}
